﻿/******************************************************************************
 *
 * @copyright:          Copyright 2011 UniSky Ltd.
 * @file:
 * @author:              kenping.liu
 * @creation:
 * @description:
 *
 * @modifications
 * date         user                description
 *
 *
 * @more-details
 *
 *****************************************************************************/

#ifndef _UNISKY_XML_H_
#define _UNISKY_XML_H_

#include "u_util.h"

U_NAMESPACE_BEGIN(u)
U_NAMESPACE_BEGIN(xml)

// xml attribute
typedef struct _st_kp_attr_
{
    _st_kp_attr_(const char* _Name="", const char* _Value="") : name(_Name), value(_Value)
    {}

    std::string name;
    std::string value;
}Attribute;

// xml Element
typedef struct _st_kp_element_
{
    _st_kp_element_(const char* _Name="", _st_kp_element_* _Parent=NULL) : name(_Name), parent(_Parent)
    {}

    void clear()
    {
        name.erase();
        value.erase();

        attributes.clear();
        children.clear();
    }

    Attribute& get_attribute(const std::string& _Name)
    {
        std::string n = _Name;
        u::util::Str::trim(n);
        for ( size_t i=0; i<attributes.size(); i++ )
        {
            if ( attributes[i].name == n )
            {
                return attributes[i];
            }
        }

        Attribute attr;
        attr.name = _Name;
        attributes.push_back(attr);
        return attributes[attributes.size()-1];
    }

    void set_attribute(const std::string& _Name, const char* _Value, bool _Overwrite=true)
    {
        get_attribute(_Name).value.erase();
        get_attribute(_Name).value.append(_Value);
    }

    void set_attribute(const std::string& _Name, int _Value, bool _Overwrite=true)
    {
        char tmp[32] = {0};
        u_sprintf(tmp, "%d", _Value);
        get_attribute(_Name).value.erase();
        get_attribute(_Name).value.append(tmp);
    }

    _st_kp_element_& set_child(const char* name)
    {
        children.push_back(_st_kp_element_(name));
        return children.at(children.size()-1);
    }

    std::string name;
    std::string value;

    std::vector<Attribute>       attributes;
    std::vector<_st_kp_element_> children;

    _st_kp_element_*             parent;
}Element;

typedef std::vector<Attribute>::iterator A_Iter;
typedef std::vector<Element>::iterator   E_Iter;

// xml DOM helper class
class Helper
{
public:
    // parse from a string
    static void parse(Element& node, const std::string& str);
    // build a Element to(append) a string
    static void build(std::string& output, Element& node, const std::string& indent="");

    // load from a xml file
    static bool load(Element& root, const char* filename, bool utf8=false);
    // save to a xml file
    static bool save(Element& root, const char* filename, bool utf8=false, const char* present="");

    static Element* get_child(Element* node, const std::string& name, bool create_new=true);
    static Element* query_by_path(Element* root, const std::string& path, bool create_new=true);
    static Element* query_child(Element* node, const Attribute* attr_list, int count,
        bool create_new=false, const std::string& name="");
    static Element* query_node(Element* node, const std::string& name);
    
    static bool         query_attribute(std::string& value, const Element* node, const std::string& name);
    static int          get_attribute_int(const Element* element, const std::string& name, int init_v=0);
    static UINT         get_attribute_uint(const Element* element, const std::string& name, UINT init_v=0);
    static bool         get_attribute_bool(Element* element, const std::string& name, bool init_v=false);
    static std::string  get_attribute_string(const Element* element, const std::string& name, const std::string& init_v="");

    static std::string encode(const std::string& _Value);
    static std::string decode(const std::string& _Value);

private:
    static void arrange(Element* node);

    struct Entity
    {
        const char* str;
        size_t      length;
        char		chr;
    };
    enum
    {
        NUM_ENTITY = 7,
        MAX_ENTITY_LENGTH = 6
    };
    static Entity entities[NUM_ENTITY];
};

U_NAMESPACE_END(xml)
U_NAMESPACE_END(u)

#endif
